﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Configuration;
using System.Collections.Specialized;
using System.Web;

namespace NetAcademia.Configuration
{
    /// <summary>
    /// Ez egy konfig olvasó osztály a XamlToPng beállításaihoz
    /// </summary>
    /// <remarks>
    /// konfigurációs élesítés:
    /// <code>
    /// <![CDATA[
    /// <configSections>
    /// ...
    ///     <section name="xamlToPng" type="NetAcademia.Configuration.XamlToPngSection"/>
    /// </configSections>
    /// ]]>
    /// </code>
    /// </remarks>
    /// <example>
    /// A config szekció, aminek az értelmezését végzi:
    /// <code>
    /// <![CDATA[
    ///   <xamlToPng>
    ///    <xamlTemplates ...>
    ///      <add .../>
    ///    </xamlTemplates>
    ///    <data>
    ///      <add .../>
    ///    </data>
    ///  </xamlToPng>
    /// ]]>
    /// </code>
    /// </example>

    public class XamlToPngSection : ConfigurationSection
    {
        private static readonly ConfigurationProperty xamlTemplates;
        private static readonly ConfigurationProperty data;

        public XamlToPngSection() { }

        static XamlToPngSection()
        {
            XamlToPngSection.xamlTemplates = new ConfigurationProperty("xamlTemplates", typeof(XamlToPngXamlTemplateCollection), null, ConfigurationPropertyOptions.None);
            XamlToPngSection.data = new ConfigurationProperty("data", typeof(XamlToPngDataCollection), null, ConfigurationPropertyOptions.None);
        }

        /// <summary>
        /// A bekonfigurálható, nevesített adatrajzoló beállításokat tartalmazó szekció
        /// </summary>
        [ConfigurationProperty("xamlTemplates")]
        public XamlToPngXamlTemplateCollection XamlTemplates
        {
            get
            {
                return (XamlToPngXamlTemplateCollection)base[XamlToPngSection.xamlTemplates];
            }
        }

        /// <summary>
        /// A <see cref="XamlTemplates"/>-ben definiálható bejegyzések által hivatkozható alapértelmezett adatcsomagok listája
        /// </summary>
        [ConfigurationProperty("data")]
        public XamlToPngDataCollection Data
        {
            get
            {
                return (XamlToPngDataCollection)base[XamlToPngSection.data];
            }
        }
    }

    /// <summary>
    /// Az adatrajzoló nevesített beállításainak listája.
    /// </summary>

    public class XamlToPngXamlTemplateCollection : ConfigurationElementCollection
    {
        private readonly ConfigurationProperty defaultConnectionStringName;

        /// <summary>
        /// Ebben a konstruktorban inicializáljuk a listaelem egyetlen lehetséges attribútumát
        /// </summary>
        public XamlToPngXamlTemplateCollection()
        {
            this.defaultConnectionStringName = new ConfigurationProperty("defaultConnectionStringName", typeof(string), null, null, new StringValidator(1), ConfigurationPropertyOptions.None);
        }

        /// <summary>
        /// Példányosítunk egy új listatagot 
        /// </summary>
        /// <returns></returns>
        protected override ConfigurationElement CreateNewElement()
        {
            return new XamlToPngXamlTemplate();
        }

        /// <summary>
        /// Visszaadja egy listaelem azonosítóját (az a string amit a web.configban az add elem name attribútumába írtunk)
        /// </summary>
        /// <param name="element">A listaelem, aminek a nevére vagyunk kíváncsiak</param>
        /// <returns></returns>
        protected override object GetElementKey(ConfigurationElement element)
        {

            return ((XamlToPngXamlTemplate)element).Key;
        }

        /// <summary>
        /// Név alapján egy konfigurációs listaelem elkérése
        /// </summary>
        /// <param name="key">A keresett add bejegyzés neve</param>
        /// <returns>A beállításokat tartalmazó objektum</returns>
        public XamlToPngXamlTemplate GetByKey(string key)
        {
            return (XamlToPngXamlTemplate)base.BaseGet(key);
        }

        /// <summary>
        /// Sorszám szerinti indexelési lehetőség, hogy a listaelemeket pozíció szerint is el lehessen érni
        /// </summary>
        /// <param name="index">A listaelem sorszáma</param>
        /// <returns>A beállításokat tartalmazó objektum</returns>
        public XamlToPngXamlTemplate this[int index]
        {
            get
            {
                return (XamlToPngXamlTemplate)base.BaseGet(index);
            }
            set
            {
                if (base.BaseGet(index) != null)
                {
                    base.BaseRemoveAt(index);
                }
                this.BaseAdd(index, value);
            }
        }

        /// <summary>
        /// A listaelemeknél be kell állítani egy tárolteljárás nevet és egy connectionStringet. 
        /// Ez utóbbi kihagyható, ha a <c>blobEntries</c> ezen attrib]tumával beállítunk egy alapértelmezett connectionStringet
        /// </summary>
        [ConfigurationProperty("defaultConnectionStringName")]
        public string DefaultConnectionStringName
        {
            get
            {
                return (string)base[this.defaultConnectionStringName];
            }
            set
            {
                base[this.defaultConnectionStringName] = value;
            }
        }

    }
    
    /// <summary>
    /// Az adatrajzoló beállításai által használható alapértelmezett adatcsomagok listája
    /// </summary>

    public class XamlToPngDataCollection : ConfigurationElementCollection
    {

        /// <summary>
        /// Példányosítunk egy új listatagot 
        /// </summary>
        /// <returns></returns>
        protected override ConfigurationElement CreateNewElement()
        {
            return new XamlToPngData();
        }

        /// <summary>
        /// Visszaadja egy listaelem azonosítóját (az a string amit a web.configban az add elem name attribútumába írtunk)
        /// </summary>
        /// <param name="element">A listaelem, aminek a nevére vagyunk kíváncsiak</param>
        /// <returns></returns>
        protected override object GetElementKey(ConfigurationElement element)
        {

            return ((XamlToPngData)element).Key;
        }

        /// <summary>
        /// Név alapján egy konfigurációs listaelem elkérése
        /// </summary>
        /// <param name="key">A keresett add bejegyzés neve</param>
        /// <returns>A beállításokat tartalmazó objektum</returns>
        public XamlToPngData GetByKey(string key)
        {
            return (XamlToPngData)base.BaseGet(key);
        }

        /// <summary>
        /// Sorszám szerinti indexelési lehetőség, hogy a listaelemeket pozíció szerint is el lehessen érni
        /// </summary>
        /// <param name="index">A listaelem sorszáma</param>
        /// <returns>A beállításokat tartalmazó objektum</returns>
        public XamlToPngData this[int index]
        {
            get
            {
                return (XamlToPngData)base.BaseGet(index);
            }
            set
            {
                if (base.BaseGet(index) != null)
                {
                    base.BaseRemoveAt(index);
                }
                this.BaseAdd(index, value);
            }
        }
    }

    /// <summary>
    /// Egy nevesített beállítás
    /// </summary>

    public class XamlToPngXamlTemplate : ConfigurationElement
    {
        private readonly ConfigurationProperty key;
        private readonly ConfigurationProperty connectionStringName;
        private readonly ConfigurationProperty command;
        private readonly ConfigurationProperty xaml;

        private readonly ConfigurationProperty data;
        private readonly ConfigurationProperty assetsBasePath;
        private readonly ConfigurationProperty imageFormat;

        /// <summary>
        /// Az attribútumok inicializálását elvégző konstruktor
        /// </summary>
        public XamlToPngXamlTemplate()
        {
            this.key = new ConfigurationProperty("key", typeof(string), null, null, new StringValidator(1), ConfigurationPropertyOptions.IsKey | ConfigurationPropertyOptions.IsRequired);
            this.connectionStringName = new ConfigurationProperty("connectionStringName", typeof(string), null, ConfigurationPropertyOptions.None);
            this.command = new ConfigurationProperty("command", typeof(string), "", ConfigurationPropertyOptions.None);
            this.data = new ConfigurationProperty("data", typeof(string), "", ConfigurationPropertyOptions.None);
            this.xaml = new ConfigurationProperty("xaml", typeof(string), "", ConfigurationPropertyOptions.IsRequired);
            this.assetsBasePath = new ConfigurationProperty("assetsBasePath", typeof(string), "", ConfigurationPropertyOptions.None);
            this.imageFormat = new ConfigurationProperty("imageFormat", typeof(NetAcademia.Web.Mvc.ImageRendering.GeneratedImageFormat?), null, null, null, ConfigurationPropertyOptions.None);

        }

        /// <summary>
        /// Az azonosítást (és hivatkozási alapot) szolgáló name attribútum
        /// </summary>
        [ConfigurationProperty("key", IsRequired = true, IsKey = true)]
        public string Key
        {
            get
            {
                return (string)base[this.key];
            }
            set
            {
                base[this.key] = value;
            }
        }

        /// <summary>
        /// A web.config connectionStrings szekciójában található connectionStringek egyikére való hivatkozás
        /// </summary>
        [ConfigurationProperty("connectionStringName")]
        public string ConnectionStringName
        {
            get
            {
                return (string)base[this.connectionStringName];
            }
            set
            {
                base[this.connectionStringName] = value;
            }
        }


        /// <summary>
        /// Egy tárolteljárás neve, amely az adatbázisból egy rekordot visszaad.
        /// Paramétereit nem itt határozzuk meg, hanem használatakor a QueryString fogja azokat tartalmazni.
        /// A visszaadott rekord oszlopai a XAML file-ban (<see cref="Xaml"/> property-ben megadva) Bindinggal hivatkozhatók.
        /// </summary>
        [ConfigurationProperty("command")]
        public string Command
        {
            get
            {
                return (string)base[this.command];
            }
            set
            {
                base[this.command] = value;
            }
        }

        /// <summary>
        /// Áthivatkozás a data szekció egy elemére statikus adatokért, amik alapértelmezett adatnak nyilvánulnak
        /// </summary>
        [ConfigurationProperty("data")]
        public string Data
        {
            get
            {
                return (string)base[this.data];
            }
            set
            {
                base[this.data] = value;
            }
        }

        /// <summary>
        /// A megjelenítéshez használt XAML elérési útja (pl.: ~/adatlap.xaml), amiben az összeszedett adatokat (data szekció, adatbázis, QueryString) Binding segítségével fel lehet használni.
        /// </summary>
        [ConfigurationProperty("xaml", IsRequired = true)]
        public string Xaml
        {
            get
            {
                return (string)base[this.xaml];
            }
            set
            {
                base[this.xaml] = value;
            }
        }


        /// <summary>
        /// Ha egy string property ~/-el kezdődik, akkor azt erre cserélje ki.
        /// </summary>
        /// <remarks>
        /// Az ASP.Net-ben használatos relatív elérési út szimulálására
        /// </remarks>
        [ConfigurationProperty("assetsBasePath")]
        public string AssetsBasePath
        {
            get
            {
                return (string)base[this.assetsBasePath];
            }
            set
            {
                base[this.assetsBasePath] = value;
            }
        }

        [ConfigurationProperty("imageFormat")]
        public NetAcademia.Web.Mvc.ImageRendering.GeneratedImageFormat ImageFormat
        {
            get
            {
                return (NetAcademia.Web.Mvc.ImageRendering.GeneratedImageFormat?)base[this.imageFormat] ?? NetAcademia.Web.Mvc.ImageRendering.GeneratedImageFormat.Png;
            }
            set
            {
                base[this.imageFormat] = value;
            }
        }
        
    }

    /// <summary>
    /// Alapértelmezett adatcsomag, amely a nevesített beállítások által hivatkozható.
    /// </summary>
    /// <remarks>
    /// Ez egy szabad elem, amit a data (<see cref="XamlToPngDataCollection"/>) listába add segítségével lehet felvenni.
    /// Akármilyen nevű attribútuma lehet. Ezek az attribútum nevek lesznek a <see cref="XamlToPngXamlTemplate.Xaml"/> által megadott XAML-ben Bindinggal elérhetők.
    /// </remarks>

    public class XamlToPngData : ConfigurationElement
    {
        public readonly Dictionary<string,string> Attributes;
        private readonly ConfigurationProperty name;

        /// <summary>
        /// Az attribútumok inicializálását elvégző konstruktor
        /// </summary>
        public XamlToPngData()
        {
            this.name = new ConfigurationProperty("key", typeof(string), null, null, new StringValidator(1), ConfigurationPropertyOptions.IsKey | ConfigurationPropertyOptions.IsRequired);
            this.Attributes = new Dictionary<string, string>();
        }

        protected override bool OnDeserializeUnrecognizedAttribute(string name, string value)
        {
            ConfigurationProperty property = new ConfigurationProperty(name, typeof(string), value);
            this.Attributes.Add(name,value);
            base[property] = value;
            //this.Parameters[name] = value;
            return true;
        }


        /// <summary>
        /// Az azonosítást (és hivatkozási alapot) szolgáló name attribútum
        /// </summary>
        [ConfigurationProperty("key", IsRequired = true, IsKey = true)]
        public string Key
        {
            get
            {
                return (string)base[this.name];
            }
            set
            {
                base[this.name] = value;
            }
        }
    }

}

/*

<xamlToPng>
  <xamlTemplates defaultConnectionStringName="alma">
	<add name="first"command="selectSomething" xaml="fancy.xaml" 
		data="additionalData" strecth="Uniform"  connectionStringName="barack" />
  </xamlTemplates>
  <data>
    <add name="additionalData" someProperty="SomeText" otherProperty="OtherText"/>
  </data>
</xamlToPng>


 * xamlTemplates
 * -------------
 * command          egy tárolteljárás neve, paraméterek az urlből, az urlben aláhúzással kezdődő paraméterek adatnak számítank
 * xaml             egy xaml file relatív elérési útja, az aktuális skintől vagy az alkalmazásgyökértől ebben a sorrendben
 * data             plusz statikus adatok configból
 * 
 * urlben           name= &_pluszadat= &_továbbiadat= &spparam1= &spparam2=
 * 
 * data
 * -------
 * minden attribute egy vele azonos nevű property a datasource-on  (dataror?, vagy hogyan hozok létre runtime dinamikusan property-ket? Binding expression? Ahogy a property browsernek?)
 *  ICustomTypeDescriptor
 *  
 * ha a command több sort ad vissza?
 *  1. használjuk az elsőt
 *  2. egymás alá, vagy mellé vagy valhogy ismételjünk?
 * 
*/
